package com.example.jpa.crud.model;

import com.example.jpa.crud.annotation.CrudField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class ResourceModel {

    private static final Logger log = LoggerFactory.getLogger(ResourceModel.class);

    private static final DefaultReplaceStrategy defaultReplaceStrategy = new DefaultReplaceStrategy();

    private String name;

    private String tableName;

    private String IdName;

    private Class<?> entityClass;

    private Class<?> IdClass;

    private boolean autoGenerateId;

    private Map<String, Field> fields;

    private Map<String, String> fieldToColumn;

    private Map<String, String> columnToField;

    private Map<String, Function<Object, Object>> visibleFields;

    public Map<String, Function<Object, Object>> getVisibleFields() {
        return visibleFields;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public String getIdName() {
        return IdName;
    }

    public void setIdName(String idName) {
        IdName = idName;
    }

    public Class<?> getEntityClass() {
        return entityClass;
    }

    public void setEntityClass(Class<?> entityClass) {
        this.entityClass = entityClass;
    }

    public Class<?> getIdClass() {
        return IdClass;
    }

    public void setIdClass(Class<?> idClass) {
        IdClass = idClass;
    }

    public boolean getAutoGenerateId() {
        return autoGenerateId;
    }

    public void setAutoGenerateId(boolean autoGenerateId) {
        this.autoGenerateId = autoGenerateId;
    }

    public Map<String, Field> getFields() {
        return fields;
    }

    public void setFields(Map<String, Field> fields) {
        this.fields = fields;
        this.fieldToColumn = null;
        this.columnToField = null;
    }

    public Map<String, String> getFieldToColumn() {
        return fieldToColumn;
    }

    public void setFieldToColumn(Map<String, String> fieldToColumn) {
        this.fieldToColumn = fieldToColumn;
    }

    public Map<String, String> getColumnToField() {
        return columnToField;
    }

    public void setColumnToField(Map<String, String> columnToField) {
        this.columnToField = columnToField;
    }

    @SuppressWarnings("unchecked")
    public void registerDisplayStrategy(Map<String, DisplayStrategy> fieldToDisplayStrategy) {
        this.visibleFields = new HashMap<>();
        for (String field : fields.keySet()) {
            final DisplayStrategy displayStrategy = fieldToDisplayStrategy.get(field);
            if (displayStrategy == DisplayStrategy.DEFAULT) {
                this.visibleFields.put(field, defaultReplaceStrategy);
            } else if (displayStrategy == DisplayStrategy.REPLACE) {
                final CrudField crudField = this.fields.get(field).getDeclaredAnnotation(CrudField.class);
                if (crudField != null) {
                    final Class<? extends Function<?, ?>> replaceStrategy = crudField.replace();
                    if (replaceStrategy != null) {
                        try {
                            final Constructor<? extends Function<?, ?>> constructor = replaceStrategy.getDeclaredConstructor();
                            constructor.setAccessible(true);
                            final Function<Object, Object> function = (Function<Object, Object>) constructor.newInstance();
                            this.visibleFields.put(field, function);
                        } catch (Exception e) {
                            log.error("registerDisplayStrategy", e);
                            this.visibleFields.remove(field);
                        }
                    }
                }
            }
        }
    }

}
